import React, { Component } from 'react';

export default class G6Graph extends Component {
  state = { graph: null };

  componentDidMount() {
    const { jsonData } = this.props;
    this.readData(jsonData, this.init());
  }

  componentWillReceiveProps(nextProps) {
    const { jsonData } = this.props;
    if (nextProps.jsonData && !jsonData) {
      this.readData(nextProps.jsonData);
    }
  }

  init = () => {
    const { id = 'mountNode', width: proWidth, height: proHeight } = this.props;
    const Mapper = window.G6.Plugins['tool.d3.mapper'];
    const { forceSimulation, forceLink, forceManyBody, forceX, forceY, forceCollide } = window.d3;
    // const nodeSizeMapper = new Mapper('node', 'size', 'size', [22, 110], {
    //   legendCfg: null,
    // });
    let simulation;
    const { clientWidth, clientHeight } = this.root.parentNode;
    const graph = new window.G6.Graph({
      container: id,
      width: proWidth || clientWidth,
      height: proHeight || clientHeight,
      // plugins: [nodeSizeMapper],
      // fitView: 'autoZoom',
      modes: {
        default: ['rightPanCanvas'],
      },
      layout: (nodes, edges) => {
        if (simulation) {
          simulation.alphaTarget(0.3).restart();
        } else {
          simulation = forceSimulation(nodes)
            .force('charge', forceManyBody().strength(-100))
            // .force(
            //   'link',
            //   forceLink(edges).id(model => {
            //     return model.id;
            //   })
            // )
            .force(
              'collision',
              forceCollide().radius(model => {
                return 40 + model.size / 2;
              })
              // .strength(0.1)
            )
            .force('y', forceY())
            // .force('y', forceY().strength(2))
            .force('x', forceX())
            .on('tick', () => {
              graph.updateNodePosition();
            });
        }
      },
    });
    graph.node({
      style: model => {
        if (model.degree === 1) {
          return {
            fill: 'r(0.5, 0.5, 0.5) 0:rgba(45, 89, 224, 0.1) 1:rgba(45, 89, 224, 0.4)',
            shadowColor: 'rgba(45, 89, 224, 0.8)',
            shadowBlur: 8,
            shadowOffsetY: 2,
            stroke: '#2D59E0',
          };
        }
        return {
          fill: 'r(0.5, 0.5, 0.5) 0:rgba(45, 89, 224, 0.1) 1:rgba(45, 89, 224, 0.4)',
          shadowColor: 'rgba(45, 89, 224, 0.64)',
          shadowBlur: 3,
          shadowOffsetY: 1,
          stroke: '#2D59E0',
        };
      },
      label: model => {
        if (model.degree === 1) {
          return {
            text: model.name,
            fontSize: 18,
            stroke: null,
            fill: '#fff',
          };
        }
        return {
          text: model.name,
          fontSize: 14,
          stroke: null,
          fill: '#fff',
        };
      },
      labelOffsetY: model => {
        return model.degree === 1 ? 0 : -(model.size / 2 + 10);
      },
    });
    graph.edge({
      style: () => {
        return {
          stroke: 'rgba(100, 141, 251, 0.4)',
          lineWidth: 1,
        };
      },
    });
    // 拖拽节点交互
    let subject = void 0; // 逼近点
    graph.on('mousedown', ev => {
      if (ev.domEvent.button === 0) {
        subject = simulation.find(ev.x, ev.y);
      }
    });

    graph.on('dragstart', ev => {
      if (subject) simulation.alphaTarget(0.3).restart();
    });

    graph.on('drag', ev => {
      if (subject) {
        subject.fx = ev.x;
        subject.fy = ev.y;
      }
    });

    graph.on('mouseup', resetState);
    graph.on('canvas:mouseleave', resetState);

    function resetState() {
      if (subject) {
        simulation.alphaTarget(0);
        subject.fx = null;
        subject.fy = null;
        subject = null;
      }
    }

    const edges = graph.getEdges();

    edges.forEach(edge => {
      edge.getGraphicGroup().set('capture', false); // 移除边的捕获，提升图形拾取效率
    });

    this.setState({ graph });
    return graph;
  };

  readData = (jsonData, graph) => {
    if (!jsonData) return;
    if (!graph) ({ graph } = this.state);
    graph.read(jsonData);
    graph.translate(graph.getWidth() / 2, graph.getHeight() / 2);
    graph.zoom(window.viewportScale);
  };

  render() {
    const { id = 'mountNode' } = this.props;
    return <div id={id} ref={e => (this.root = e)} />;
  }
}
